package com.pig4cloud.pig.ads.service.ks.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.sdk.client.DyKsClient;
import com.dy.sdk.model.request.ks.KsAccessTokenRequest;
import com.dy.sdk.model.request.ks.KsAdvertiserInfoRequest;
import com.dy.sdk.model.request.ks.KsLuopanRequest;
import com.dy.sdk.model.response.ks.KsResponse;
import com.dy.sdk.utils.DyException;
import com.google.api.client.util.Lists;
import com.pig4cloud.pig.ads.config.SdkProperties;
import com.pig4cloud.pig.ads.pig.mapper.ks.KsAccesstokenMapper;
import com.pig4cloud.pig.ads.service.AdAccountService;
import com.pig4cloud.pig.ads.service.AdAgentService;
import com.pig4cloud.pig.ads.service.AdvertiserService;
import com.pig4cloud.pig.ads.service.ks.KsAccesstokenService;
import com.pig4cloud.pig.ads.utils.DateUtils;
import com.pig4cloud.pig.api.entity.AdAccount;
import com.pig4cloud.pig.api.entity.AdAgent;
import com.pig4cloud.pig.api.entity.KsAccesstoken;
import com.pig4cloud.pig.api.entity.KsAccountToken;
import com.pig4cloud.pig.api.util.Constants;
import com.pig4cloud.pig.api.util.JsonUtil;
import com.pig4cloud.pig.api.vo.AdAccountAgentVo;
import com.pig4cloud.pig.api.vo.KsAccesstokenReq;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.util.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 快手授权token表
 * @author  chenxiang
 * @version  2022-03-22 20:29:09
 * table: ks_accesstoken
 */
@Log4j2
@Service("ksAccesstokenService")
@RequiredArgsConstructor
public class KsAccesstokenServiceImpl extends ServiceImpl<KsAccesstokenMapper, KsAccesstoken> implements KsAccesstokenService {

	private final AdAccountService adAccountService;

	private final AdAgentService adAgentService;

	private final SdkProperties sdkProperties;

	private final AdvertiserService advertiserService;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	/**
	 * 账户授权
	 * @param req
	 * @return
	 */
	@Override
	@Async
	public R saveAuth(KsAccesstokenReq req){
		String ksAppId = sdkProperties.getKsAppId();
		String ksSecret = sdkProperties.getKsSecret();
		String authCode = req.getAuthCode();
		Integer userId = req.getUserId();
		Date date = new Date();
		try{
			// 获取token
			DyKsClient ksClient = new DyKsClient("", ksAppId, ksSecret);
			KsAccessTokenRequest tokenRequest = new KsAccessTokenRequest();
			tokenRequest.setAuth_code(authCode);
			String result = ksClient.getAccessToken(tokenRequest);
			log.info(">>>>>>获取token:{}",result);
			KsResponse response = JSON.parseObject(result, KsResponse.class);

			if ("0".equals(response.getCode())){
				// 驼峰转换  KsAccesstoken 对象
				JSONObject jsonObj = JsonUtil.toSnakeObject(response.getData().toJSONString(), JSONObject.class);
				KsAccesstoken ksAccesstoken = JSON.toJavaObject(jsonObj, KsAccesstoken.class);
				String accessToken = ksAccesstoken.getAccessToken();

				List<String> advertiserIds = JSONObject.parseArray(JSONArray.parseArray(ksAccesstoken.getAdvertiserIds()).toJSONString(), String.class);
				if (CollectionUtils.isNotEmpty(advertiserIds)){
					// 获取广告账户信息
					JSONObject objectAdvertiserInfo = getKsAdvertiserInfo(ksClient, advertiserIds.get(0), accessToken);
					String housekeeper = objectAdvertiserInfo.getString("user_id");
					String corporationName = objectAdvertiserInfo.getString("corporation_name");

					ksAccesstoken.setAppId(ksAppId);
					ksAccesstoken.setSecret(ksSecret);
					ksAccesstoken.setAuthCode(authCode);
					// 将快手user_id作为管家账户ID保存KsAccesstoken表
					ksAccesstoken.setAdvertiserId(housekeeper);

					KsAccesstoken token = this.getOne(Wrappers.<KsAccesstoken>lambdaQuery().eq(KsAccesstoken::getAdvertiserId,housekeeper).eq(KsAccesstoken::getDeleted,0).last("LIMIT 1"));
					if (Objects.nonNull(token)){
						ksAccesstoken.setTokenTime(date);
						ksAccesstoken.setUpdateTime(date);
						ksAccesstoken.setUpdateId(Long.valueOf(userId));
						// 更新 ksAccesstoken
						this.updateById(ksAccesstoken);
					}else{
						ksAccesstoken.setTokenTime(date);
						ksAccesstoken.setCreateTime(date);
						ksAccesstoken.setCreateId(Long.valueOf(userId));
						// 保存 ksAccesstoken
						this.save(ksAccesstoken);
					}

					final List<AdAccountAgentVo.Advertiser> advertiserList = Lists.newArrayList();
					// 更新ad_account 和 tt_advertiser
					saveAccount(ksClient, housekeeper, corporationName, accessToken, advertiserIds, advertiserList);

					// 授权代理商
					Integer agentId = req.getAgentId();
					if (Objects.nonNull(agentId)){
						saveAgent(agentId, userId, advertiserList);
					}

				}
			}else{
				log.error("获取token异常：{}",response.getMessage());
				return R.failed(response.getMessage());
			}
		} catch(DyException ze){
			log.error("快手授权异常：{}",ze.getMsg());
			ze.printStackTrace();
		}catch (Exception e) {
			log.error("快手授权异常：{}",e.getMessage());
			e.printStackTrace();
		}
		return R.ok(null,"授权成功");
	}

	/**
	 * 更新ad_account
	 * @param ksClient
	 * @param housekeeper
	 * @param accessToken
	 * @param advertiserIds
	 */
	public void saveAccount(DyKsClient ksClient, String housekeeper, String corporationName, String accessToken, List<String> advertiserIds, List<AdAccountAgentVo.Advertiser> advertiserList){
		List<AdAccount> addAccountList = Lists.newArrayList();
		// 将管家账户保存到ad_account
		AdAccount accountHousekeeper = adAccountService.getOne(Wrappers.<AdAccount>lambdaQuery().eq(AdAccount::getAdvertiserId,housekeeper).eq(AdAccount::getIsDelete,0).last("LIMIT 1"));
		if (Objects.isNull(accountHousekeeper)){
			AdAccount adAccount = new AdAccount();
			adAccount.setMediaCode(PlatformTypeEnum.KS.getValue());
			adAccount.setMediaName(PlatformTypeEnum.KS.getDescription());
			adAccount.setAdvertiserId(housekeeper);
			adAccount.setAdvertiserName(corporationName);
			adAccount.setHousekeeper(housekeeper);
			adAccount.setCreateTime(new Date());
			adAccount.setUpdateTime(new Date());
			addAccountList.add(adAccount);
		}

		// 已经加挂的广告账户
		QueryWrapper<AdAccount> wrapperAcc = new QueryWrapper<>();
		wrapperAcc.eq("media_code", PlatformTypeEnum.KS.getValue());
		wrapperAcc.eq("is_delete",0);
		List<AdAccount> accountsList = adAccountService.list(wrapperAcc);

		// 获取罗盘所有账户
		JSONObject luoPanInfo = getKsLuoPanInfo(ksClient, housekeeper, accessToken);
		List<Map> luoPanInfoMap = JSONObject.parseArray(JSONArray.parseArray(luoPanInfo.getString("details")).toJSONString(), Map.class);
		for (Map map : luoPanInfoMap){
			String advertiserId = String.valueOf(map.get("advertiser_id"));
			String advertiserName = String.valueOf(map.get("advertiser_name"));
			map.put("housekeeper",housekeeper);
			// 设置代理商使用账户信息集合
			advertiserList.add(new AdAccountAgentVo.Advertiser(advertiserId, advertiserName));

			// 验证账户是否已经加挂
			List<AdAccount> accounts = accountsList.stream().filter(v -> v.getAdvertiserId().equals(advertiserId)).collect(Collectors.toList());
			// 验证是否属于本次加挂的账户 ， 如果不是生效状态设置为：失效
			List<String> advList = advertiserIds.stream().filter(v -> v.equals(advertiserId)).collect(Collectors.toList());
			Integer effectiveStatus = 1;
			map.put("deleted",0);
			if (CollectionUtils.isEmpty(advList)){
				effectiveStatus = 2;
				map.put("deleted",1);
			}
			if (CollectionUtils.isEmpty(accounts)){
				AdAccount adAccount = new AdAccount();
				adAccount.setMediaCode(PlatformTypeEnum.KS.getValue());
				adAccount.setMediaName(PlatformTypeEnum.KS.getDescription());
				adAccount.setAdvertiserId(advertiserId);
				adAccount.setAdvertiserName(advertiserName);
				adAccount.setHousekeeper(housekeeper);
				adAccount.setEffectiveStatus(effectiveStatus);
				adAccount.setCreateTime(new Date());
				addAccountList.add(adAccount);
			}else{
				AdAccount account = accounts.get(0);
				account.setAdvertiserName(advertiserName);
				account.setHousekeeper(housekeeper);
				account.setEffectiveStatus(effectiveStatus);
				account.setUpdateTime(new Date());
				addAccountList.add(account);
			}

		}
		if (CollectionUtil.isNotEmpty(luoPanInfoMap)) {
			advertiserService.saveAdvertiser(luoPanInfoMap, PlatformTypeEnum.KS.getValue());
		}
		if (CollectionUtils.isNotEmpty(addAccountList)){
			adAccountService.saveUpdateList(addAccountList);
		}
		// 删除token缓存
		List<String> advertiserIdList = luoPanInfoMap.stream().map(map -> String.valueOf(map.get("advertiser_id"))).collect(Collectors.toList());
		delRedisTokenBatch(advertiserIdList);
	}
	public void saveAgent(Integer agentId, Integer userId, List<AdAccountAgentVo.Advertiser> advertiserList){
		// 为广告账户设置代理
		AdAgent agent = adAgentService.getOne(Wrappers.<AdAgent>lambdaQuery().select(AdAgent::getAgentName).eq(AdAgent::getId, agentId).eq(AdAgent::getIsDelete, 0));
		if (Objects.nonNull(agent)) {
			AdAccountAgentVo adAccountAgentVo = new AdAccountAgentVo();
			adAccountAgentVo.setAgentId(String.valueOf(agentId));
			adAccountAgentVo.setAgentName(agent.getAgentName());
			adAccountAgentVo.setEffectiveTime(DateUtils.dateToString(new Date()));
			adAccountAgentVo.setAdvertisers(advertiserList);
			adAccountService.batchAddAccountAgent(adAccountAgentVo, userId);
		}
	}
	/**
	 * 获取广告账户信息
	 * @param ksClient
	 * @param advertiserId
	 * @param accessToken
	 * @return
	 */
	public JSONObject getKsAdvertiserInfo(DyKsClient ksClient, String advertiserId ,String accessToken){
		try {
			// 获取广告账户信息
			KsAdvertiserInfoRequest advertiserInfo = new KsAdvertiserInfoRequest();
			advertiserInfo.setAdvertiser_id(advertiserId);
			String resultAdvertiserInfo = ksClient.call4Post(advertiserInfo,accessToken);
			KsResponse ksResponse = JSON.parseObject(resultAdvertiserInfo, KsResponse.class);
			if ("0".equals(ksResponse.getCode())){
				return ksResponse.getData();
			}else{
				log.error("获取广告账户信息异常：{}",ksResponse.getMessage());
			}
		} catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 获取罗盘绑定广告主列
	 * @param ksClient
	 * @param ksUserId
	 * @param accessToken
	 * @return
	 */
	public JSONObject getKsLuoPanInfo(DyKsClient ksClient, String ksUserId ,String accessToken){
		try {
			// 获取罗盘绑定广告主列
			KsLuopanRequest luoPanInfo = new KsLuopanRequest();
			luoPanInfo.setAdvertiser_id(ksUserId);
			String resultluoPanInfo = ksClient.call4Post(luoPanInfo,accessToken);
			KsResponse ksResponse = JSON.parseObject(resultluoPanInfo, KsResponse.class);
			if ("0".equals(ksResponse.getCode())){
				return ksResponse.getData();
			}else{
				log.error("获取罗盘绑定广告主列异常：{}",ksResponse.getMessage());
			}
		} catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 批量删除redis缓存
	 * @param advertiserIdList
	 */
	public void delRedisTokenBatch(List<String> advertiserIdList){
		if (CollectionUtils.isNotEmpty(advertiserIdList)) {
			for (String advertiserId : advertiserIdList) {
				// 删除token缓存
				stringRedisTemplate.delete(Constants.REDIS_KS_TOKEN_KEY_PRIX + advertiserId);
			}
		}
	}
}


